//
//  ETH+Transaction+Signer.swift
//  XHWalletUtils
//
//  Created by xinph on 2020/5/20.
//  Copyright © 2020 xinph. All rights reserved.
//

import Foundation

extension ETH: SignerProtocol {
    public func signTX(_ ts: TransactionConvertible, password: String, from: AddressConvertible) -> Result<SignedResultType> {
        guard let mgr = ETH.web3?.provider.attachedKeystoreManager, let account = EthereumAddress(from.asAddress()) else {
            return .failure(XHError(signerError))
        }
        var transaction = createEthereumTransaction(ts)
        do {
            try Web3Signer.signTX(transaction: &transaction, keystore: mgr, account: account, password: password)
            //// doit
        } catch {
            ///////doit
        }

        return .failure(XHError(signerError))
    }
    
    /// ETH签名
    public func signTX(_ ts: TransactionConvertible, password: String) -> coswift.Promise<SignedResultType> {
        let promise = coswift.Promise<SignedResultType>()
        
        co_launch {
            let rst = try await(promise: self.smartContracts(ts: ts, password: password))
            switch rst {
            case .fulfilled(let contractsResult):
                if let hash = contractsResult?.hash, let transaction = contractsResult?.transaction {
                    promise.fulfill(value: ETHResult(signedTx: transaction.txid ?? "", txHash: transaction.txhash ?? "", hash: hash))
                } else {
                    promise.reject(error: XHError(signerError))
                }
            default: promise.reject(error: XHError(signerError))
            }
        }
        
        return promise
    }
    
    
    fileprivate func createEthereumTransaction(_ ts: TransactionConvertible) -> EthereumTransaction {

        let ether = EthereumTransaction(gasPrice: BigUInt(ts.gasPrice),
                                      gasLimit: BigUInt(ts.gasLimit),
                                      to: EthereumAddress(ts.to.asAddress())!,
                                      value: BigUInt(ts.value),
                                      data: ts.data ?? Data())
        return ether
    }
    
    /// 开启签名
    /// - Parameter ts: 交易信息
    private func smartContracts(ts: TransactionConvertible, password: String) -> coswift.Promise<TransactionSendingResult?> {
        let promise = coswift.Promise<TransactionSendingResult?>()
        
        guard let address = self.ethKeystore?.addresses?.first?.address, let chain = ETH.web3 else {
            promise.reject(error: XHError(signerError))
            return promise
        }
        chain.provider.network = nil
       
        guard let contract = chain.contract(abiString, at: EthereumAddress(ts.to.asAddress())) else {
            promise.reject(error: XHError(signerError))
            return promise
        }

        var options = TransactionOptions.defaultOptions
        options.from = EthereumAddress(address)
        options.value = BigUInt(ts.value)
        options.gasLimit = TransactionOptions.GasLimitPolicy.manual(BigUInt(ts.gasLimit))
        options.gasPrice = TransactionOptions.GasPricePolicy.manual(BigUInt(ts.gasPrice))
        
//        do {
//            try chain.eth.sendTransactionPromise(createEthereumTransaction(ts), transactionOptions: options, password: password)
//                .done({ (rst) in
//                    promise.fulfill(value: rst)
//                }).catch({ (err) in
//                    promise.reject(error: err)
//                    print(err)
//                })
//        }
//        
//        
//        
//        chain.eth.sendTransaction(EthereumAddress(ts.to.asAddress()), transactionOptions: TransactionOptions, password: password)






        let transactionIntermediate = contract.method("transactions", parameters: [ts.proposalId] as [AnyObject], transactionOptions: options)

        let res = transactionIntermediate?.callPromise(transactionOptions: options)
            .done({ (res) in
                if res["executed"] as? Int != 0 {
                    promise.reject(error: XHError(signerError))
                } else {
                    if let confirmTransaction = contract.method("confirmTransaction", parameters: [ts.proposalId] as [AnyObject], transactionOptions: options) {

                        confirmTransaction.sendPromise(password: password, transactionOptions: options)
                            .done { (rst) in
                                promise.fulfill(value: rst)
                        }.catch { (error) in
                            print(error)
                            promise.reject(error: error)
                        }
                    } else {
                        promise.reject(error: XHError(signerError))
                    }
                }

            }).catch({ (err) in
                print(err)
                promise.reject(error: XHError(signerError))
            })

        return promise
   }
}
